
// === uuStyle ===
// depend: uuMeta, uuColor
/*
uuStyle.toPixel(elm, value) - return pixel value
uuStyle.getPixel(elm, prop) - return pixel value
uuStyle.getBGImg(elm) - return "http://..." or ""
uuStyle.getBGColor(elm, ancestor = false) - return [color, alpha]
uuStyle.getOpacity(elm) - return 0.0 ~ 1.0
uuStyle.setOpacity(elm, opacity = 1.0, diff = false)
uuStyle.getActualDimension(image) - return { w, h }
uuStyle.getViewport() - return { w, h, sx, sy }
uuStyle.getRect(elm) - return { x, y, w, h, ow, oh }
uuStyle.setRect(elm, { x, y, w, h })
 */
(function() {
var _style, // inner namespace
    _mm = uuMeta,
    _win = window,
    _doc = document,
    _int = parseInt,
    _float = parseFloat,
    _ie = _mm.ie,
    _opera = _mm.opera,
    _webkit = _mm.webkit,
    _ieroot = _mm.quirks ? "body" : "documentElement",
    _runstyle = _mm.runstyle,
    TRANSPARENT = "transparent",
    IMPORTANT = "important",
    POSITION = "position",
    ABSOLUTE = "absolute",
    DISPLAY = "display",
    BLOCK = "block",
    LEFT = "left";

_style = {
  // uuStyle.toPixel - covert unit
  //    toPixel(node, 123)    -> 123
  //    toPixel(node, "12px") -> 12
  //    toPixel(node, "12pt") -> 16
  //    toPixel(node, "12em") -> 192
  toPixel: function(elm,          // @param Node: context
                    value,        // @param String/Number:
                    accurately) { // @param Boolena(= false): false = quick
                                  // @return Number: pixel value
    var rv, st, rs, mem1, mem2, mem3, fontSize;

    if (typeof value === "string") {
      if (value.lastIndexOf("px") > 0) { // value is pixel unit
        return _int(value) || 0;
      }

      if (!accurately) {
        // quick
        rv = _float(value);
        if (value.lastIndexOf("pt") > 0) {
          rv *= 4 / 3; // 1.333...
        } else if (value.lastIndexOf("em") > 0) {
          fontSize = (_ie ? elm[_runstyle]
                          : _runstyle(elm, "")).fontSize;
          if (fontSize.lastIndexOf("pt") > 0) { // 12pt * 1.333 = 16px
            rv *= _float(fontSize) * 4 / 3;
          } else {
            rv *= _float(fontSize); // 12px
          }
        }
        return _int(rv) || 0;
      }

      st = elm.style, mem1 = st[LEFT];
      if (_ie) {
        rs = elm.runtimeStyle, mem2 = rs[LEFT]; // keep !important value
        // overwrite
        rs[LEFT] = elm[_runstyle][LEFT];
        st[LEFT] = value;
        // get pixel
        value = st.pixelLeft;
        // restore
        st[LEFT] = mem1;
        rs[LEFT] = mem2;
      } else {
        // overwrite
        if (_webkit) {
          mem2 = st.getPropertyValue(POSITION);
          mem3 = st.getPropertyValue(DISPLAY);
          st.setProperty(POSITION, ABSOLUTE, IMPORTANT);
          st.setProperty(DISPLAY,  BLOCK,    IMPORTANT);
        }
        st.setProperty(LEFT, value, IMPORTANT);
        // get pixel
        value = _int(_runstyle(elm, "")[LEFT]);
        // restore
        st.removeProperty(LEFT);
        st.setProperty(LEFT, mem1, "");
        if (_webkit) {
          st.removeProperty(POSITION);
          st.removeProperty(DISPLAY);
          st.setProperty(POSITION, mem2, "");
          st.setProperty(DISPLAY,  mem3, "");
        }
      }
    }
    return value || 0;
  },

  // uuStyle.getPixel - get pixel value
  //    getPixel(node, "left")
  //    getPixel(node, "width")
  getPixel: function(elm,    // @param Node:
                     prop) { // @param String: style property name
                             // @return Number: pixel value
    function dim(horizontal) {
      var r = elm.getBoundingClientRect();
      return horizontal ? (r.right - r.left) : (r.bottom - r.top);
    }
    var rv;

    if (_ie) {
      switch (prop) {
      case "width":  return elm.clientWidth  || dim(1);
      case "height": return elm.clientHeight || dim(0);
      }
      rv = elm[_runstyle][prop];
      (rv === "auto") && (rv = _style.toPixel(elm, rv));
    } else {
      rv = _runstyle(elm, "")[prop];
    }
    return _int(rv) || 0;
  },

  // uuStyle.getBGImg - get background-image url
  getBGImg: function(elm) { // @param Node:
                            // @return String: "http://..." or ""
    var bg = "backgroundImage", m,
        url = _ie ? (elm.style[bg] || elm[_runstyle][bg])
                  : _runstyle(elm, "")[bg];
    if (url) {
      if ( (m = /^url\((.*)\)$/.exec(url)) ) {
        return m[1].replace(/^\s*[\"\']?|[\"\']?\s*$/g, ""); // trim quote
      }
    }
    return "";
  },

  // uuStyle.getBGColor - get background-color (from ancestor)
  // depend: uuColor
  getBGColor: function(elm,        // @param Node:
                       ancestor) { // @param Boolean(= false):
                                   // @return Array: [ColorString, Alpha]
    var bgc = "backgroundColor", n = elm, color = TRANSPARENT;

    if (!ancestor) {
      return _ie ? (elm.style[bgc] || elm[_runstyle][bgc])
                 : _runstyle(elm, "")[bgc];
    }
    while (n && color === TRANSPARENT) {
      if ((_ie && n[_runstyle]) || !_ie) {
        color = _ie ? n[_runstyle][bgc]
                    : _runstyle(elm, "")[bgc];
      }
      n = n.parentNode;
    }
    return (color === TRANSPARENT) ? ["white", 1] : uuColor.parse(color);
  },

  // uuStyle.getOpacity - get opacity value(from 0.0 to 1.0)
  getOpacity: function(elm) { // @param Node:
                              // @return Number: float(from 0.0 to 1.0)
    var v = elm.style.opacity,
        ftm = (v === "" || v === void 0); // first time

    return _float(ftm ? (_ie ? 1 : _runstyle(elm, "").opacity) : v);
  },

  // uuStyle.setOpacity - set opacity value(from 0.0 to 1.0)
  setOpacity: function(elm,    // @param Node:
                       opa,    // @param Number(= 1.0): float(from 0.0 to 1.0)
                       diff) { // @param Boolean(= false):
    opa = (opa === void 0) ? 1 : _float(opa);
    var st = elm.style, v = st.opacity,
        ftm = (v === "" || v === void 0); // first time

    v = _float(ftm ? (_ie ? 1 : _runstyle(elm, "").opacity) : v);
    diff && (opa += v);
    if (opa > 0.999) {
      opa = 1;
    } else if (opa < 0.001) {
      opa = 0;
    }

    if (v !== opa) {
      st.opacity = opa; // update / bond
      if (_ie) {
        if (ftm) {
          st.filter += " alpha(opacity=0)";
          st.zoom = st.zoom || "1"; // IE6, IE7: force "hasLayout"
        }
        elm.filters.alpha.opacity = (opa * 100) | 0;

        if (v === 1) { // curt === 1 and opa !== 1
          elm.filters.alpha.enabled = true;
        } else if (opa === 1) { // curt !== 1 and opa === 1
          elm.filters.alpha.enabled = false;
        }
      }
    }
  },

  // uuStyle.getActualDimension
  // http://d.hatena.ne.jp/uupaa/20090602/1243933843
  getActualDimension: function(image) { // @param HTMLImageElement
                                        // @return Hash: { w, h }
    var run, mem, w, h, key = "actual";

    // for Firefox, Safari, Chrome
    if ("naturalWidth" in image) {
      return { w: image.naturalWidth, h: image.naturalHeight };
    }

    if ("src" in image) { // HTMLImageElement
      if (image[key] && image[key].src === image.src) {
        return image[key];
      }
      if (_ie) { // for IE
        run = image.runtimeStyle;
        mem = { w: run.width, h: run.height }; // keep runtimeStyle
        run.width  = "auto"; // override
        run.height = "auto";
        w = image.width;
        h = image.height;
        run.width  = mem.w; // restore
        run.height = mem.h;
      } else { // for Opera
        mem = { w: image.width, h: image.height }; // keep current style
        image.removeAttribute("width");
        image.removeAttribute("height");
        w = image.width;
        h = image.height;
        image.width  = mem.w; // restore
        image.height = mem.h;
      }
      return image[key] = { w: w, h: h, src: image.src }; // bond
    }
    // HTMLCanvasElement
    return { w: image.width, h: image.height };
  },

  // uuStyle.getViewport - get viewport dimension and scroll offset
  getViewport: function() { // @return { w, h, sx, sy }
    var e = _win;

    if (_ie) {
      e = _doc[_ieroot];
      return { w: e.clientWidth  || e.scrollWidth,
               h: e.clientHeight || e.scrollHeight,
               sx: e.scrollLeft,
               sy: e.scrollTop };
    }
    // "window.pageXOffset" alias "window.scrollX" in gecko, webkit
    return { w: e.innerWidth,
             h: e.innerHeight,
             sx: e.pageXOffset,
             sy: e.pageYOffset };
  },

  // uuStyle.getRect - get element absolute position and rectangle
  getRect: function(elm) { // @param Node:
                           // @return Hash: { x, y, w, h, ow, oh }
    var e, x = 0, y = 0, w = 0, h = 0, fix = 0, rect, vp;

    if (elm.getBoundingClientRect) {
      // get relative position
      rect = elm.getBoundingClientRect();
      fix = (_ie && elm.parentNode === _doc.body) ? 2 : 0;
      // to absolute position
      vp = _style.getViewport();
      x = rect.left + vp.sx - fix;
      y = rect.top  + vp.sy - fix;
      w = rect.right - rect.left;
      h = rect.bottom - rect.top;
    } else {
      // get absolute position(for Fx2)
      e = elm;
      while (e) {
        x += e.offsetLeft || 0;
        y += e.offsetTop  || 0;
        e  = e.offsetParent;
      }
    }
    return {
      // element position(absolute)
      x: x,
      y: y,
      // element dimension(style.width + padding)
      w: elm.clientWidth  || w,
      h: elm.clientHeight || h,
      // element dimension(style.width + padding + border)
      ow: elm.offsetWidth,
      oh: elm.offsetHeight
    };
  },

  // uuStyle.setRect - set element rect
  setRect: function(elm,    // @param Node:
                    rect) { // @param Hash: { x, y, w, h }
    var s = elm.style;

    if (_ie || _opera) {
      if ("x" in rect) { s.pixelLeft   = rect.x; }
      if ("y" in rect) { s.pixelTop    = rect.y; }
      if ("w" in rect) { s.pixelWidth  = rect.w > 0 ? rect.w : 0; }
      if ("h" in rect) { s.pixelHeight = rect.h > 0 ? rect.h : 0; }
    } else {
      if ("x" in rect) { s.left   = rect.x + "px"; }
      if ("y" in rect) { s.top    = rect.y + "px"; }
      if ("w" in rect) { s.width  = (rect.w > 0 ? rect.w : 0) + "px"; }
      if ("h" in rect) { s.height = (rect.h > 0 ? rect.h : 0) + "px"; }
    }
  }
};

// --- initialize ---

// --- export ---
_win.uuStyle = _style; // window.uuStyle

})(); // uuStyle scope
